package com.ebor.utils.utils;

import com.google.gson.Gson;
import com.mysql.cj.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;

import java.util.HashMap;
import java.util.Map;

@Component
@Slf4j
@AllArgsConstructor
public class RedisUtil {

    private final JedisCluster jedisCluster;

    /**
     * 设置缓存
     *
     * @param key   缓存key
     * @param value 缓存value
     */
    public void set(String key, String value) {
        jedisCluster.set(key, value);
    }

    /**
     * 设置缓存
     *
     * @param key          键
     * @param value        值
     * @param cacheSeconds 超时时间，0为不超时
     * @return result
     */
    public String set(String key, String value, int cacheSeconds) {
        String result = null;

        try {
            result = jedisCluster.set(key, value);
            if (cacheSeconds != 0) {
                jedisCluster.expire(key, cacheSeconds);
            }
            log.debug("set {} = {}", key, value);
        } catch (Exception e) {
            log.warn("set {} ", key, e);
        }
        return result;
    }

    /**
     * 设置缓存对象
     *
     * @param key 缓存key
     * @param obj 缓存value
     */
    public <T> void setObject(String key, T obj, int expireTime) {
        Gson gson = new Gson();
        jedisCluster.setex(key, expireTime, gson.toJson(obj));
    }

    /**
     * 判断当前key值 是否存在
     *
     * @param key key
     */
    public boolean hasKey(String key) {
        return jedisCluster.exists(key);
    }


    /**
     * 设置缓存，并且自己指定过期时间
     *
     * @param key        key
     * @param value      value
     * @param expireTime 过期时间
     */
    public void setWithExpireTime(String key, String value, int expireTime) {
        jedisCluster.setex(key, expireTime, value);
    }


    /**
     * 获取指定key的缓存
     *
     * @param key key
     */
    public String get(String key) {
        return jedisCluster.get(key);
    }

    /**
     * 删除指定key的缓存
     *
     * @param key key
     */
    public void delete(String key) {
        jedisCluster.del(key);
    }

    /**
     * 返回 -2 表示这个key已过期，已不存在
     * 返回 -1 表示这个key没有设置有效期
     * 返回0以上的值 表示是这个key的剩余有效时间
     *
     * @param key key
     * @return ttl
     */
    public Long ttl(String key) {
        return jedisCluster.ttl(key);
    }

    /**
     * 设置Map缓存
     *
     * @param key          键
     * @param value        值
     * @param cacheSeconds 超时时间，0为不超时
     * @return String
     */
    public String setMap(String key, Map<String, String> value, int cacheSeconds) {
        String result = null;
        try {
            if (jedisCluster.exists(key)) {
                jedisCluster.del(key);
            }
            result = jedisCluster.hmset(key, value);
            if (cacheSeconds != 0) {
                jedisCluster.expire(key, cacheSeconds);
            }
            log.info("setMap {} ", key);
        } catch (Exception e) {
            log.error("setMap {} ", key, e);
        }
        return result;
    }

    /**
     * 获取Map缓存
     *
     * @param key 键
     * @return 值
     */
    public Map<String, String> getMap(String key) {
        Map<String, String> value = null;
        try {
            if (jedisCluster.exists(key)) {
                value = jedisCluster.hgetAll(key);
                log.info("getMap {} ", key);
            }
        } catch (Exception e) {
            log.error("getMap {} ", key, e);
        }
        return value;
    }

    /**
     * 获取Map缓存
     *
     * @param key 键
     * @return 值
     */
    public Map<String, Object> getObjectMap(String key) {
        Map<String, Object> value = null;

        try {
            if (jedisCluster.exists(getBytesKey(key))) {
                value = new HashMap<>(1);
                Map<byte[], byte[]> map = jedisCluster.hgetAll(getBytesKey(key));
                for (Map.Entry<byte[], byte[]> e : map.entrySet()) {
                    value.put(StringUtils.toString(e.getKey()), toObject(e.getValue()));
                }
                log.info("getObjectMap {} ", key);
            }
        } catch (Exception e) {
            log.error("getObjectMap {} ", key, e);
        }
        return value;
    }

    /**
     * 设置Map缓存
     *
     * @param key          键
     * @param value        值
     * @param cacheSeconds 超时时间，0为不超时
     * @return String
     */
    public String setObjectMap(String key, Map<String, Object> value,
                               int cacheSeconds) {
        String result = null;

        try {
            if (jedisCluster.exists(getBytesKey(key))) {
                jedisCluster.del(key);
            }
            Map<byte[], byte[]> map = new HashMap<>(value.size());
            for (Map.Entry<String, Object> e : value.entrySet()) {
                map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));
            }
            result = jedisCluster.hmset(getBytesKey(key), (Map<byte[], byte[]>) map);
            if (cacheSeconds != 0) {
                jedisCluster.expire(key, cacheSeconds);
            }
            log.info("setObjectMap {} ", key);
        } catch (Exception e) {
            log.error("setObjectMap {} ", key, e);
        }
        return result;
    }


    /**
     * 获取byte[]类型Key
     *
     * @param object object
     * @return byte[]
     */
    public byte[] getBytesKey(Object object) {
        if (object instanceof String) {
            return StringUtils.getBytes((String) object);
        } else {
            return ObjectUtils.serialize(object);
        }
    }

    /**
     * byte[]型转换Object
     *
     * @param bytes bytes
     * @return Object
     */
    public Object toObject(byte[] bytes) {
        return ObjectUtils.unSerialize(bytes);
    }

    /**
     * Object转换byte[]类型
     *
     * @param object object
     * @return byte[]
     */
    public byte[] toBytes(Object object) {
        return ObjectUtils.serialize(object);
    }
}